package com.zmn.mcc.dubbo.impl.organize;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.business.interfaces.organize.OrganizeBService;
import com.zmn.mcc.common.constant.OrganizeConsts;
import com.zmn.mcc.common.dto.organize.BsOrgDIO;
import com.zmn.mcc.common.dto.organize.BsOrgDRO;
import com.zmn.mcc.common.dto.organize.OrganizeDRO;
import com.zmn.mcc.dubbo.dto.DubboConsts;
import com.zmn.mcc.dubbo.interfaces.organize.OrganizeListRemoteService;
import com.zmn.mcc.model.entity.organize.McOrganize;
import com.zmn.mcc.model.entity.staff.McStaff;
import com.zmn.mcc.services.interfaces.organize.OrganizeService;
import com.zmn.mcc.services.interfaces.staff.StaffService;
import org.apache.dubbo.config.annotation.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanCopier;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tanbiao
 * @description
 * @modifier
 * @since 2020/6/24 10:23
 **/
@Service(version = DubboConsts.INTERFACE_VERSION, validation = "true")
public class OrganizeListRemoteServiceImpl implements OrganizeListRemoteService {
    private final Logger logger = LoggerFactory.getLogger(OrganizeListRemoteServiceImpl.class);

    private static final String TAG = "组织架构dubbo接口";

    @Resource
    private OrganizeBService organizeBService;
    @Resource
    private OrganizeService organizeService;

    @Resource
    private StaffService staffService;


    @Override
    @ReadOnlyConnection
    public ResponseDTO<OrganizeDRO> getByKey(Integer orgId) {

        if (NumberUtil.isNullOrZero(orgId)) {
            return ResponseDTO.fail("没有指定组织ID");
        }

        McOrganize organize = organizeService.findByKey(orgId);
        if (Objects.isNull(organize)) {
            return ResponseDTO.fail(String.format("[%s]对应的组织机构不存在", orgId));
        }

        // 对象转换
        BeanCopier copier = BeanCopier.create(McOrganize.class, OrganizeDRO.class, false);
        OrganizeDRO organizeDRO = new OrganizeDRO();
        copier.copy(organize, organizeDRO, null);


        logger.info(String.format("[%s]取得组织对象,dept:[%s]", TAG, JSONObject.toJSONString(organize)));
        return ResponseDTO.success(organizeDRO, "OK");
    }

    @Override
    public ResponseDTO<OrganizeDRO> getByCompanyId(Integer companyId) {

        if (NumberUtil.isNullOrZero(companyId)) {
            return ResponseDTO.fail("没有指定公司ID");
        }
        List<McOrganize> mcOrganizes = organizeService.listByCompanyId(companyId);
        if (CollectionUtil.isNullOrEmpty(mcOrganizes)) {
            return ResponseDTO.fail(String.format("[%s]对应的组织机构不存在", companyId));
        }
        McOrganize organize = mcOrganizes.get(0);

        // 对象转换
        BeanCopier copier = BeanCopier.create(McOrganize.class, OrganizeDRO.class, false);
        OrganizeDRO organizeDRO = new OrganizeDRO();
        copier.copy(organize, organizeDRO, null);

        // 负责人信息
        if (Objects.nonNull(organize.getManagerId())) {
            McStaff staff = Optional.ofNullable(staffService.findByKey(organizeDRO.getManagerId()))
                                    .orElse(new McStaff());
            organizeDRO.setManagerName(staff.getRealName());
            organizeDRO.setManagerPhone(staff.getMobile());
        }

        logger.info(String.format("[%s]取得组织对象,dept:[%s]", TAG, JSONObject.toJSONString(organizeDRO)));
        return ResponseDTO.success(organizeDRO, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<OrganizeDRO>> listByLevel(Integer level, Integer status) {

        return this.listByPlatAndLevel(null, level, status);
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<OrganizeDRO>> listByPlatAndLevel(Integer plat, Integer level, Integer status) {

        List<McOrganize> organizes = organizeBService.listByPlatAndLevel(plat, level, status);

        // 对象转换
        List<OrganizeDRO> items = this.parseToOrganizeDRO(organizes);

        logger.info(String.format("[%s]取得组织对象列表,plat:[%s],level:[%s],status:[%s]", TAG, plat, level, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listVtByPlatAndLevel(Integer plat, Integer level, Integer status) {

        List<McOrganize> organizes = organizeBService.listByPlatAndLevel(plat, level, status);

        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(organizes);

        logger.info(String.format("[%s]取得组织Vt对象列表,plat:[%s],level:[%s],status:[%s]", TAG, plat, level, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listVtByPlatAndLevelAndParentIds(Integer plat, Integer level, Integer status, List<Integer> parentIdList) {
        List<McOrganize> organizes = organizeBService.listByPlatsAndLevelAndParentIds(Objects.isNull(plat) ? null : Collections.singletonList(plat), level, status, parentIdList);
        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(organizes);

        logger.info(String.format("[%s]取得组织Vt对象列表,plat:[%s],level:[%s],status:[%s]", TAG, plat, level, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<List<VtDTO>> listVtByPlatsAndLevelAndParentIds(List<Integer> plats, Integer level, Integer status, List<Integer> parentIdList) {
        List<McOrganize> organizes = organizeBService.listByPlatsAndLevelAndParentIds(plats, level, status, parentIdList);
        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(organizes);

        logger.info(String.format("[%s]取得组织Vt对象列表,plat:[%s],level:[%s],status:[%s]", TAG, plats, level, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<OrganizeDRO>> listByParentId(Integer parentId) {
        return this.listByParentId(parentId, GlobalDict.STATUS_ENABLE);
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<OrganizeDRO>> listByParentId(Integer parentId, Integer status) {

//        if (NumberUtil.isNullOrZero(parentId)) {
//            return ResponseDTO.fail("没有指定上级组织ID");
//        }

        List<McOrganize> organizes = organizeService.listByParentId(parentId, status);

        // 对象转换
        List<OrganizeDRO> items = this.parseToOrganizeDRO(organizes);

        logger.info(String.format("[%s]取得下级组织对象列表,parentId:[%s],status:[%s]", TAG, parentId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<VtDTO>> listVtByParentId(Integer parentId, Integer status) {

        if (NumberUtil.isNullOrZero(parentId)) {
            return ResponseDTO.fail("没有指定上级组织ID");
        }

        List<McOrganize> organizes = organizeService.listByParentId(parentId, status);

        // 对象转换
        List<VtDTO> items = this.parseToVtDTO(organizes);

        logger.info(String.format("[%s]取得下级组织Vt对象列表,parentId:[%s],status:[%s]", TAG, parentId, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    @ReadOnlyConnection
    public ResponseDTO<List<OrganizeDRO>> listByOrgIds(List<Integer> orgIds, Integer status) {

        if (CollectionUtil.isNullOrEmpty(orgIds)) {
            return ResponseDTO.fail("组织ID集合不能为空");
        }

        List<McOrganize> organizes = organizeService.listByOrgIds(orgIds, status);

        // 对象转换
        List<OrganizeDRO> items = this.parseToOrganizeDRO(organizes);

        logger.info(String.format("[%s]取得下级组织对象列表,orgIds:[%s],status:[%s]", TAG, orgIds, status));
        return ResponseDTO.success(items, "OK");
    }

    @Override
    public ResponseDTO<List<BsOrgDRO>> listBsOrgByOrgId(List<Integer> orgIds) {
        if (CollectionUtil.isNullOrEmpty(orgIds)) {
            return ResponseDTO.fail("未指定组织ID");
        }

        // 查询组织信息
        List<McOrganize> organizes = organizeService.listByOrgIds(orgIds);
        if (CollectionUtil.isNullOrEmpty(organizes)) {
            return ResponseDTO.success(new ArrayList<>(0), "OK");
        }

        // 组装返回数据
        List<BsOrgDRO> result = new ArrayList<>(organizes.size());
        for (McOrganize organize : organizes) {
            BsOrgDRO dro = BsOrgDRO.builder().orgId(organize.getOrgId()).operateType(OrganizeConsts.OPERATE_TYPE_SELECT).build();
            // 转换负责人
            if (Objects.nonNull(organize.getManagerId())) {
                McStaff manager = staffService.findByKey(organize.getManagerId());
                if (Objects.nonNull(manager)) {
                    dro.setBsManagerId(manager.getBsUserId());
                }
            }
            // 转换直属领导
            if (Objects.nonNull(organize.getLeaderId())) {
                McStaff leader = staffService.findByKey(organize.getLeaderId());
                if (Objects.nonNull(leader)) {
                    dro.setBsLeaderId(leader.getBsUserId());
                }
            }
            result.add(dro);
        }

        return ResponseDTO.success(result, "OK");
    }

    @Override
    public ResponseDTO<String> saveBsOrgInfo(List<BsOrgDIO> list) {
        logger.info("[{}]同步北森组织信息开始：{}", TAG, list);

        // 参数校验
        if (CollectionUtil.isNullOrEmpty(list)) {
            logger.info("[{}]同步北森组织信息结束，同步的组织信息为空", TAG);
            return ResponseDTO.fail("同步的组织信息不能为空");
        }

        // 待更新组织
        List<BsOrgDIO> waitUpdateBsOrg = list.stream().filter(e -> Objects.equals(e.getOperateType(), OrganizeConsts.OPERATE_TYPE_UPDATE)).collect(Collectors.toList());
        if (CollectionUtil.isNullOrEmpty(waitUpdateBsOrg)) {
            logger.info("[{}]同步北森组织信息结束，同步的信息中没有需要更新的数据", TAG);
            return ResponseDTO.fail("同步的信息中没有需要更新的数据");
        }

        // 更新组织信息
        List<McOrganize> waitUpdateOrganize = organizeService.listByOrgIds(waitUpdateBsOrg.stream().map(BsOrgDIO::getOrgId).collect(Collectors.toList()));
        for (McOrganize organize : waitUpdateOrganize) {
            Optional<BsOrgDIO> match = waitUpdateBsOrg.stream().filter(e -> Objects.equals(e.getOrgId(), organize.getOrgId())).findFirst();
            if (!match.isPresent()) {
                continue;
            }
            BsOrgDIO dio = match.get();
            // 转换负责人
            if (Objects.nonNull(dio.getBsManagerId())) {
                McStaff manager = staffService.findByBsUserId(dio.getBsManagerId());
                organize.setManagerId(Objects.nonNull(manager) ? manager.getStaffId() : null);
            } else {
                organize.setManagerId(null);
            }
            // 转换直属领导
            if (Objects.nonNull(dio.getBsLeaderId())) {
                McStaff leader = staffService.findByBsUserId(dio.getBsLeaderId());
                organize.setLeaderId(Objects.nonNull(leader) ? leader.getStaffId() : null);
            } else {
                organize.setLeaderId(null);
            }
            organizeService.updateBsOrg(organize);
        }

        logger.info("[{}]同步北森组织信息结束", TAG);

        return ResponseDTO.success("OK");
    }


    /**
     * 把原始的组织对象McOrganize转换为VtDTO对象
     *
     * @param organizes
     * @return List<OrganizeDRO>
     */
    private List<VtDTO> parseToVtDTO(List<McOrganize> organizes) {

        List<VtDTO> items = new ArrayList<>();

        for (McOrganize organize : organizes) {
            items.add(new VtDTO(organize.getOrgId(), organize.getOrgName()));
        }
        return items;
    }

    /**
     * 把原始的组织对象McDept转换为Dubbo出参对象
     *
     * @param organizes
     * @return List<DeptDRO>
     */
    private List<OrganizeDRO> parseToOrganizeDRO(List<McOrganize> organizes) {

        List<OrganizeDRO> items = new ArrayList<>();

        // 对象转换
        BeanCopier copier = BeanCopier.create(McOrganize.class, OrganizeDRO.class, false);
        for (McOrganize organize : organizes) {
            OrganizeDRO organizeDRO = new OrganizeDRO();
            copier.copy(organize, organizeDRO, null);
            items.add(organizeDRO);
        }
        return items;
    }
}
